package org.millioncall.yueyoga.common.utils;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Part;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.support.AbstractMultipartHttpServletRequest;

//Last modified by zangjy on 2012-3-31
//Last modified by zangjy on 2012-5-5
public class CosMultipartHttpServletRequest extends AbstractMultipartHttpServletRequest {
	protected static final Logger logger = LoggerFactory.getLogger(CosMultipartHttpServletRequest.class);
	private final CosMultipartRequest multipartRequest;

	protected CosMultipartHttpServletRequest(HttpServletRequest request, CosMultipartRequest multipartRequest) {
		super(request);
		this.multipartRequest = multipartRequest;
		setMultipartFiles(initFileMap(multipartRequest));
	}

	public CosMultipartRequest getMultipartRequest() {
		return multipartRequest;
	}

	// 初始化所有文件
	private MultiValueMap<String, MultipartFile> initFileMap(CosMultipartRequest multipartRequest) {
		MultiValueMap<String, MultipartFile> files = new LinkedMultiValueMap<String, MultipartFile>();
		Set<String> fileNames = multipartRequest.getFileNames();
		for(String fileName : fileNames) {
			files.add(fileName, new CosMultipartFile(fileName));
		}
		return files;
	}

	public Enumeration<String> getParameterNames() {
		return this.multipartRequest.getParameterNames();
	}

	public String getParameter(String name) {
		return this.multipartRequest.getParameter(name);
	}

	public String[] getParameterValues(String name) {
		return this.multipartRequest.getParameterValues(name);
	}

	public Map<String, String[]> getParameterMap() {
		Map<String, String[]> params = new HashMap<String, String[]>();
		Enumeration<String> names = getParameterNames();
		while (names.hasMoreElements()) {
			String name = names.nextElement();
			params.put(name, getParameterValues(name));
		}
		return Collections.unmodifiableMap(params);
	}

	private class CosMultipartFile implements MultipartFile {
		private final String name;
		private final File file;
		private final long size;

		public CosMultipartFile(String name) {
			this.name = name;
			this.file = multipartRequest.getFile(this.name);
			this.size = (this.file != null ? this.file.length() : 0);
		}

		public String getName() {
			return name;
		}

		public String getOriginalFilename() {
			String filename = multipartRequest.getOriginalFileName(this.name);
			return (filename != null ? filename : "");
		}

		public String getContentType() {
			return multipartRequest.getContentType(this.name);
		}

		public boolean isEmpty() {
			return (this.size == 0);
		}

		public long getSize() {
			return this.size;
		}

		public byte[] getBytes() throws IOException {
			if(this.file != null && !this.file.exists()) {
				throw new IllegalStateException("File has been moved - cannot be read again");
			}
			return (this.size > 0 ? FileCopyUtils.copyToByteArray(this.file) : new byte[0]);
		}

		public InputStream getInputStream() throws IOException {
			if(this.file != null && !this.file.exists()) {
				throw new IllegalStateException("File has been moved - cannot be read again");
			}
			if(this.size != 0) {
				return new FileInputStream(this.file);
			} else {
				return new ByteArrayInputStream(new byte[0]);
			}
		}

		// 上传的临时文件转移到目标文件，相当于一个剪切操作，实际为重命名操作
		public void transferTo(File dest) throws IOException, IllegalStateException {
			if(this.file != null && !this.file.exists()) {
				throw new IllegalStateException("File has already been moved - cannot be transferred again");
			}

			if(dest.exists() && !dest.delete()) {
				throw new IOException("Destination file [" + dest.getAbsolutePath() + "] already exists and could not be deleted");
			}

			boolean moved = false;
			if(this.file != null) {
				moved = this.file.renameTo(dest);
				if(!moved) {
					FileCopyUtils.copy(this.file, dest);
				}
			} else {
				dest.createNewFile();
			}

			if(logger.isDebugEnabled()) {
				logger.debug("Multipart file '" + getName() + "' with original filename [" + getOriginalFilename() + "], stored "
						+ (this.file != null ? "at [" + this.file.getAbsolutePath() + "]" : "in memory") + ": " + (moved ? "moved" : "copied") + " to [" + dest.getAbsolutePath() + "]");
			}
		}
	}

	@Override
	public HttpHeaders getMultipartHeaders(String paramOrFileName) {
		try {
			Part part = getPart(paramOrFileName);
			if(part != null) {
				HttpHeaders headers = new HttpHeaders();
				for(String headerName : part.getHeaderNames()) {
					headers.put(headerName, new ArrayList<String>(part.getHeaders(headerName)));
				}
				return headers;
			} else {
				return null;
			}
		} catch (Exception ex) {
			throw new MultipartException("Could not access multipart servlet request", ex);
		}
	}

	@Override
	public String getMultipartContentType(String paramOrFileName) {
		try {
			Part part = getPart(paramOrFileName);
			return (part != null ? part.getContentType() : null);
		} catch (Exception ex) {
			throw new MultipartException("Could not access multipart servlet request", ex);
		}
	}
}
